package com.byb.server.service.impl;

import com.byb.server.domain.ProtectScope;
import com.byb.server.domain.Rate;
import com.byb.server.repository.*;
import com.byb.server.service.ProductService;
import com.byb.server.domain.Product;
import com.byb.server.repository.search.ProductSearchRepository;
import com.byb.server.service.RateService;
import com.byb.server.service.ServiceInvService;
import com.byb.server.service.dto.*;
import com.byb.server.service.mapper.*;
import com.byb.server.service.util.*;
import com.byb.server.service.util.rebuild.SortStyService;
import com.byb.server.service.util.rebuild.StrategyRebuild;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;


import java.text.DecimalFormat;
import java.util.*;
import java.util.stream.Collectors;

import static org.elasticsearch.index.query.QueryBuilders.*;

/**
 * Service Implementation for managing Product.
 */
@Service
@Transactional
public class ProductServiceImpl implements ProductService {

    private final Logger log = LoggerFactory.getLogger(ProductServiceImpl.class);

    private final ProductRepository productRepository;

    private final ProductDetailsRepository productDetailsRepository;

    private final RateRepository rateRepository;

    private final ProductMapper productMapper;

    private final RateService rateService;

    private final ServiceInvService serviceInvService;

    private final Product_sortMapper productSortMapper;

    private final ProductDetailMapper productDetailMapper;

    private final ScoreForProductDetailMapper scoreForProductDetailMapper;

    private final ServiceInvMapper serviceInvMapper;

    private final ProtectScopeRepository protectScopeRepository;

    private final ProductSearchRepository productSearchRepository;

    @Qualifier("sortScore")
    private final SortStyService sortScore;

    @Qualifier("sortMoney")
    private final SortStyService sortMoney;

    @Qualifier("sortProtectScore")
    private final SortStyService sortProtectScore;

    private final SexRepository sexRepository;

    public ProductServiceImpl(ProductRepository productRepository, ProductDetailsRepository productDetailsRepository, RateRepository rateRepository, ProductMapper productMapper, RateService rateService, ServiceInvService serviceInvService, Product_sortMapper productSortMapper, ProductDetailMapper productDetailMapper, ScoreForProductDetailMapper scoreForProductDetailMapper, ServiceInvMapper serviceInvMapper, ProtectScopeRepository protectScopeRepository, ProductSearchRepository productSearchRepository, SortStyService sortScore, SortStyService sortMoney, SortStyService sortProtectScore, SexRepository sexRepository) {
        this.productRepository = productRepository;
        this.productDetailsRepository = productDetailsRepository;
        this.rateRepository = rateRepository;
        this.productMapper = productMapper;
        this.rateService = rateService;
        this.serviceInvService = serviceInvService;
        this.productSortMapper = productSortMapper;
        this.productDetailMapper = productDetailMapper;
        this.scoreForProductDetailMapper = scoreForProductDetailMapper;
        this.serviceInvMapper = serviceInvMapper;
        this.protectScopeRepository = protectScopeRepository;
        this.productSearchRepository = productSearchRepository;
        this.sortScore = sortScore;
        this.sortMoney = sortMoney;
        this.sortProtectScore = sortProtectScore;
        this.sexRepository = sexRepository;
    }

    /**
     * Save a product.
     *
     * @param productDTO the entity to save
     * @return the persisted entity
     */
    @Override
    public ProductDTO save(ProductDTO productDTO) {
        log.debug("Request to save Product : {}", productDTO);
        Product product = productMapper.toEntity(productDTO);
        product = productRepository.save(product);
        ProductDTO result = productMapper.toDto(product);
        //productSearchRepository.save(product);
        return result;
    }

    /**
     * Get all the products.
     *
     * @param pageable the pagination information
     * @return the list of entities
     */
    @Override
    @Transactional(readOnly = true)
    public Page<ProductDTO> findAll(Pageable pageable) {
        log.debug("Request to get all Products");
        return productRepository.findAll(pageable)
            .map(productMapper::toDto);
    }

    /**
     * Get one product by id.
     *
     * @param id the id of the entity
     * @return the entity
     */
    @Override
    @Transactional(readOnly = true)
    public ProductDTO findOne(Long id) {
        log.debug("Request to get Product : {}", id);
        Product product = productRepository.findOneWithEagerRelationships(id);
        return productMapper.toDto(product);
    }

    /**
     * Delete the  product by id.
     *
     * @param id the id of the entity
     */
    @Override
    public void delete(Long id) {
        log.debug("Request to delete Product : {}", id);
        productRepository.delete(id);
        //productSearchRepository.delete(id);
    }

    /**
     * Search for the product corresponding to the query.
     *
     * @param query    the query of the search
     * @param pageable the pagination information
     * @return the list of entities
     */
    @Override
    @Transactional(readOnly = true)
    public Page<ProductDTO> search(String query, Pageable pageable) {
        log.debug("Request to search for a page of Products for query {}", query);
        Page<Product> result = productSearchRepository.search(queryStringQuery(query), pageable);
        return result.map(productMapper::toDto);
    }

    /**
     * Search for the product corresponding to the query of KeyName
     *
     * @param query
     * @param pageable
     * @return
     */
    @Override
    @Transactional(readOnly = true)
    public Page<ProductDTO> findBywordKeysKeyName(String query, Pageable pageable) {
        log.debug("Request to search for a page of Products for query {}", query);
        Page<Product> result = productSearchRepository.findBywordKeysKeyName(query, pageable);
        return result.map(productMapper::toDto);
    }

    /**
     * 业务代码，根据orderByState 选择具体算法，并排序
     *
     * @param id
     * @param age
     * @param premiumPaymentPeriod
     * @param sexName
     * @param payment
     * @param orderByState
     * @param query
     * @param pageable
     * @return
     */
    @Override
    @Transactional(readOnly = true)
    public ProductDetail findOneById(Long id, String age, Integer premiumPaymentPeriod, String sexName, Integer payment, Integer orderByState, Collection<Long> query, Pageable pageable) {
        log.debug("Request to get ProductDetailsDTO : {}", id);
        ProductDetail productDetail = productDetailMapper.toDto(productDetailsRepository.findById(id));
        if (productDetail == null) {
            return null;
        }
        Rate rate = rateRepository.findByProductIdAndAgeAndPremiumPaymentPeriodAndSexId(id, AgeUtil.getAge(age), premiumPaymentPeriod, SexUtil.getSex_id(sexName));
        if (rate != null) {
            productDetail.setPrice(rate.getPrice());
        } else {
            return null;
        }
        if (orderByState == 0) {

        } else if (orderByState == 1) {
            Page<Product_sort> sortList = rateRepository.findByAgeAndPremiumPaymentPeriodAndSexSexName(AgeUtil.getAge(age), premiumPaymentPeriod, sexName, pageable).map(productSortMapper::toDto);
            List<Product_sort> sorts = sortList.getContent();
            for (int i = 0; i < sorts.size(); i++) {
                if (sorts.get(i).getProductId() == id) {
                    productDetail.setNum(i);
                }
            }
        }

        // productDetail.setNum(rateRepository.findOneByAgeAndPremiumPaymentPeriodAndSexSexName(AgeUtil.getAge(age),premiumPaymentPeriod, SexUtil.getSex_id(sexName),id));
        Page<Product_sort> page = rateRepository.findByAgeAndPremiumPaymentPeriodAndSexSexName(AgeUtil.getAge(age), premiumPaymentPeriod, sexName, pageable).map(productSortMapper::toDto);
        List<Product_sort> list = rateService.sortByState(orderByState, page.getContent(), payment, query, pageable);
        List<Product_sort> sets = list;
        productDetail.setProduct_sorts(sets);
        return SortUtil.moneyUtil(productDetail, payment, list);
    }

    @Override
    public ProductDetail findById(Long id, String age, Integer premiumPaymentPeriod, String sexName, Integer payment, Integer orderByState, Collection<Long> query, Pageable pageable, boolean flag) {
        ProductDetail productDetail = productDetailMapper.toDto(productDetailsRepository.findById(id));
        Page<Product_sort> page = rateService.sort(age, premiumPaymentPeriod, sexName, pageable);
        List<Product_sort> data = page.getContent().stream().sorted(Comparator.comparing(Product_sort::getPrice)).collect(Collectors.toList());
        List<Product_sort> rank;
        if (!flag) {
            rank = rateService.sortByState(1, data, payment, query, pageable);
        } else {
            rank = rateService.sortByState(orderByState, data, payment, query, pageable);
        }
        List<Product_sort> list = rateService.sortByState(orderByState, data, payment, query, pageable);

        // List<Product_sort> sor=new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {
            if (list.get(i).getProductId().equals(productDetail.getId())) {
                productDetail.setPrice(list.get(i).getPrice());
                productDetail.setNum(i + 1);
                productDetail.setAmountOfIndemnificationSocre(list.get(i).getAmountOfIndemnificationSocre());
                productDetail.setOverallScore(list.get(i).getOverallScore());
                productDetail.setStrichen_money(list.get(i).getStrichen_money());
                productDetail.setDie_money(list.get(i).getDie_money());
                productDetail.setMild_money(list.get(i).getMild_money());
                break;
                //  List<Product_sort>  ok = rateRepository.findByAgeAndPremiumPaymentPeriodAndSexSexName(AgeUtil.getAge(age), premiumPaymentPeriod, sexName, pageable).map(productSortMapper::toDto).getContent().stream().sorted(Comparator.comparing(Product_sort::getPrice)).collect(Collectors.toList());
            }

        }
        if (rank.size() == 0) {
            return null;
        }
        productDetail.setProduct_sorts(rank);
        return productDetail;
    }

    @Override
    @Transactional(readOnly = true)
    public ProductDetail findByIdRebuild(Long id, String age, Integer premiumPaymentPeriod, String sexName, Integer payment, Integer orderByState, String query,boolean flag, Pageable pageable) {
        ProductDetail productDetail = productDetailMapper.toDto(productDetailsRepository.findById(id));
        List<Product_sort> result = new ArrayList<>();
        Rate rates = rateRepository.findAllByAgeAndPremiumPaymentPeriodAndSexAndAgeAfter(AgeUtil.getAge(age), premiumPaymentPeriod, SexUtil.getSex_id(sexName));
        Product_sort product_sort01 = productSortMapper.toDto(rates);
        Gson gson = new Gson();
        if(orderByState==0){
            result = StrategyRebuild.getContext(sortScore).getProductDetail(AgeUtil.getAge(age), premiumPaymentPeriod, sexName, payment,
                gson.fromJson(query, new TypeToken<Collection<Long>>() {
                }.getType()), product_sort01, pageable);
        }else if(orderByState==1){
            result = StrategyRebuild.getContext(sortMoney).getProductDetail(AgeUtil.getAge(age), premiumPaymentPeriod, sexName, payment,
                gson.fromJson(query, new TypeToken<Collection<Long>>() {
                }.getType()), product_sort01, pageable);

        }else{
            result = StrategyRebuild.getContext(sortProtectScore).getProductDetail(AgeUtil.getAge(age), premiumPaymentPeriod, sexName, payment,
                gson.fromJson(query, new TypeToken<Collection<Long>>() {
                }.getType()), product_sort01, pageable);

        }
        for (int i = 0; i < result.size(); i++) {
            if (result.get(i).getProductId().equals(productDetail.getId())) {
                productDetail.setPrice(result.get(i).getPrice());
                productDetail.setNum(i + 1);
                productDetail.setAmountOfIndemnificationSocre(result.get(i).getAmountOfIndemnificationSocre());
                productDetail.setOverallScore(result.get(i).getOverallScore());
                productDetail.setStrichen_money(result.get(i).getStrichen_money());
                productDetail.setDie_money(result.get(i).getDie_money());
                productDetail.setMild_money(result.get(i).getMild_money());
                break;
            }
        }
        if(flag){
            DecimalFormat df = new DecimalFormat("#0.0");
            List<Product_sort> num=new ArrayList<>();
            product_sort01.setOverallScore("100");
            product_sort01.setStrichen_money(String.valueOf(df.format(payment / product_sort01.getPrice())));
            product_sort01.setAmountOfIndemnificationSocre("10");
            num.add(product_sort01);
            productDetail.setProduct_sorts(num);
        }else{
            productDetail.setProduct_sorts(result.subList(0, 3));
        }

        return productDetail;
    }

    /**
     * 评分逻辑
     *
     * @param id
     * @param productDetail
     * @return
     */
    @Override
    @Transactional(readOnly = true)
    public ProductDetailScoreDTO findProductDetailScore(Long id, ProductDetail productDetail) {
        ProductDetailScoreDTO productDetailScoreDTO = new ProductDetailScoreDTO();
        ProductDetailScoreDTO data = (ProductDetailScoreDTO) ClassReflection.reflectionAttr(productDetail, productDetailScoreDTO);
        ProtectScope protectScope = protectScopeRepository.findByProductId(id);
        if (protectScope == null) {
            return null;
        }
        Set<ServiceInvDTO> serviceInvs = serviceInvService.findAllByProductId(8L);
        productDetailScoreDTO.setServiceInvs(serviceInvs);
        return (ProductDetailScoreDTO) ClassReflection.reflectionAttr(protectScope, data);
    }

    @Override
    @Transactional(readOnly = true)
    public ProductDetailScoreDTO findByIdDetailScore(Long id, String age, Integer premiumPaymentPeriod, String sexName, Integer payment, Integer orderByState, String query, Pageable pageable) {
        ProductDetail productDetail = findByIdRebuild(id, age, premiumPaymentPeriod, sexName, payment, orderByState, query, true,pageable);
        ProductDetailScoreDTO productDetailScoreDTO = new ProductDetailScoreDTO();
        ProductDetailScoreDTO data = (ProductDetailScoreDTO) ClassReflection.reflectionAttr(productDetail, productDetailScoreDTO);
        ProtectScope protectScope = protectScopeRepository.findByProductId(id);
        if (protectScope == null) {
            return null;
        }
        Set<ServiceInvDTO> serviceInvs = serviceInvService.findAllByProductId(8L);
        productDetailScoreDTO.setServiceInvs(serviceInvs);
        ProductDetailScoreDTO a= (ProductDetailScoreDTO) ClassReflection.reflectionAttr(protectScope, data);
        return a;
    }

    @Override
    public void delectProdcutAllInfo(Long id) {
        sexRepository.proc(id);
    }
}
